package com.herui.sdyu_lib.http.param;

import android.text.TextUtils;

import com.alibaba.fastjson.JSON;
import com.herui.sdyu_lib.http.HttpMethod;
import com.herui.sdyu_lib.http.bean.KeyValue;
import com.herui.sdyu_lib.http.okhttp.OKHttpRequestCall;
import com.herui.sdyu_lib.http.okhttp.RetrofitCall;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;



/**
 * Created by amanda.shan on 2016/6/2.
 */
public abstract class BaseParams<T extends BaseParams> {

	private String charset = "UTF-8";
	private HttpMethod method;
	private String bodyContent;
	private boolean multipart = false; // 是否强制使用multipart表单

	private boolean json;

	protected List<Header> headers = new ArrayList<Header>();
	private final List<KeyValue> queryStringParams = new ArrayList<KeyValue>();
	private final List<KeyValue> bodyParams = new ArrayList<KeyValue>();
	private final List<KeyValue> fileParams = new ArrayList<KeyValue>();

	public void setCharset(String charset) {
		if (!TextUtils.isEmpty(charset)) {
			this.charset = charset;
		}
	}

	public String getCharset() {
		return charset;
	}

	public T setMethod(HttpMethod method) {
		this.method = method;
		return (T) this;
	}

	public HttpMethod getMethod() {
		return method;
	}

	public boolean isMultipart() {
		return multipart;
	}

	public T setMultipart(boolean multipart) {
		this.multipart = multipart;
		return (T) this;
	}

	public void clearParams() {
		queryStringParams.clear();
		bodyParams.clear();
		fileParams.clear();
		bodyContent = null;
	}

	/**
	 * 覆盖header
	 *
	 * @param name
	 * @param value
	 */
	public T setHeader(String name, String value) {
		Header header = new Header(name, value, true);
		Iterator<Header> it = headers.iterator();
		while (it.hasNext()) {
			KeyValue kv = it.next();
			if (name.equals(kv.key)) {
				it.remove();
			}
		}
		this.headers.add(header);
		return (T) this;
	}

	/**
	 * 添加header
	 *
	 * @param name
	 * @param value
	 */
	public T addHeader(String name, String value) {
		this.headers.add(new Header(name, value, false));
		return (T) this;
	}

	public T setBodyContent(String bodyContent) {
		this.bodyContent = bodyContent;

		return (T) this;
	}

	/**
	 * 添加请求参数(根据请求谓词, 将参数加入QueryString或Body.)
	 *
	 * @param name
	 *            参数名
	 * @param value
	 *            可以是String, File, InputStream 或 byte[]
	 */
	public T addParameter(String name, Object value) {
		if (value == null)
			return (T) this;

		if (method == null || HttpMethod.permitsRequestBody(method)) {
			if (!TextUtils.isEmpty(name)) {
				if (value instanceof File || value instanceof InputStream || value instanceof byte[]) {
					this.fileParams.add(new KeyValue(name, value));
				} else {
					if (value instanceof List) {
						for (Object item : (List) value) {
							this.bodyParams.add(new ArrayItem(name, item));
						}
					} else if (value.getClass().isArray()) {
						int len = Array.getLength(value);
						for (int i = 0; i < len; i++) {
							this.bodyParams.add(new ArrayItem(name, Array.get(value, i)));
						}
					} else {
						this.bodyParams.add(new KeyValue(name, value));
					}
				}
			} else {
				this.bodyContent = value.toString();
			}
		} else {
			if (!TextUtils.isEmpty(name)) {
				if (value instanceof List) {
					for (Object item : (List) value) {
						this.queryStringParams.add(new ArrayItem(name, item));
					}
				} else if (value.getClass().isArray()) {
					int len = Array.getLength(value);
					for (int i = 0; i < len; i++) {
						this.queryStringParams.add(new ArrayItem(name, Array.get(value, i)));
					}
				} else {
					this.queryStringParams.add(new KeyValue(name, value));
				}
			}
		}
		return (T) this;
	}

	/**
	 * 添加参数至Query String
	 *
	 * @param name
	 * @param value
	 */
	public T addQueryStringParameter(String name, String value) {
		if (!TextUtils.isEmpty(name)) {
			this.queryStringParams.add(new KeyValue(name, value));
		}
		return (T) this;
	}

	/**
	 * 添加参数至Body
	 *
	 * @param name
	 * @param value
	 */
	public T addBodyParameter(String name, String value) {
		if (!TextUtils.isEmpty(name)) {
			this.bodyParams.add(new KeyValue(name, value));
		} else {
			this.bodyContent = value;
		}
		return (T) this;
	}

	/**
	 * 添加body参数
	 */
	public T addBodyParameter(String name, File value) {
		this.fileParams.add(new KeyValue(name, value));
		return (T) this;
	}

	/**
	 * 添加body参数
	 *
	 * @param name
	 *            参数名
	 * @param value
	 *            可以是String, File, InputStream 或 byte[]
	 */
	public T addBodyParameter(String name, Object value) {
		this.fileParams.add(new KeyValue(name, value));
		return (T) this;
	}
	
	public T addJsonBodyParameter(String name, Object value) {
		
		String string = JSON.toJSONString(value);
		if (!TextUtils.isEmpty(name)) {
			this.bodyParams.add(new KeyValue(name, string));
		} else {
			this.bodyContent = string;
		}
		this.fileParams.add(new KeyValue(name, value));
		return (T) this;
	}

	public List<Header> getHeaders() {
		return new ArrayList<Header>(headers);
	}

	public List<KeyValue> getQueryStringParams() {
		checkBodyParams();
		return new ArrayList<KeyValue>(queryStringParams);
	}

	public String getBodyContent() {
		return bodyContent;
	}

	public boolean isJson() {
		return json;
	}

	public T setJson(boolean json) {
		this.json = json;
		return (T) this;
	}

	public List<KeyValue> getBodyParams() {
		checkBodyParams();
		return new ArrayList<KeyValue>(bodyParams);
	}

	public List<KeyValue> getFileParams() {
		checkBodyParams();
		return new ArrayList<KeyValue>(fileParams);
	}

	public List<KeyValue> getStringParams() {
		List<KeyValue> result = new ArrayList<KeyValue>(queryStringParams.size() + bodyParams.size());
		result.addAll(queryStringParams);
		result.addAll(bodyParams);
		return result;
	}

	public String getStringParameter(String name) {
		for (KeyValue kv : queryStringParams) {
			if (name == null && kv.key == null) {
				return kv.getValueStr();
			} else if (name != null && name.equals(kv.key)) {
				return kv.getValueStr();
			}
		}
		for (KeyValue kv : bodyParams) {
			if (name == null && kv.key == null) {
				return kv.getValueStr();
			} else if (name != null && name.equals(kv.key)) {
				return kv.getValueStr();
			}
		}
		return null;
	}

	public List<KeyValue> getParams(String name) {
		List<KeyValue> result = new ArrayList<KeyValue>();
		for (KeyValue kv : queryStringParams) {
			if (name == null && kv.key == null) {
				result.add(kv);
			} else if (name != null && name.equals(kv.key)) {
				result.add(kv);
			}
		}
		for (KeyValue kv : bodyParams) {
			if (name == null && kv.key == null) {
				result.add(kv);
			} else if (name != null && name.equals(kv.key)) {
				result.add(kv);
			}
		}
		for (KeyValue kv : fileParams) {
			if (name == null && kv.key == null) {
				result.add(kv);
			} else if (name != null && name.equals(kv.key)) {
				result.add(kv);
			}
		}
		return result;
	}

	public abstract OKHttpRequestCall buildOkhttp();
	public abstract RetrofitCall buildRetrofit();

	protected void checkBodyParams() {

		if (!TextUtils.isEmpty(bodyContent)) {
			bodyParams.clear();
			fileParams.clear();
		}

		if (!bodyParams.isEmpty() && (!HttpMethod.permitsRequestBody(method) || !TextUtils.isEmpty(bodyContent))) {
			queryStringParams.addAll(bodyParams);
			bodyParams.clear();
			fileParams.clear();
		}

		if (!bodyParams.isEmpty() && (multipart || fileParams.size() > 0)) {
			fileParams.addAll(bodyParams);
			bodyParams.clear();
		}
	}

	public final static class ArrayItem extends KeyValue {
		public ArrayItem(String key, Object value) {
			super(key, value);
		}
	}

	public final static class Header extends KeyValue {

		public final boolean setHeader;

		public Header(String key, String value, boolean setHeader) {
			super(key, value);
			this.setHeader = setHeader;
		}
	}
}
